const https = require('https');
const http = require('http');
const stream = require('stream');
const zlib = require('zlib');
const Request = require('./request');
const Header = require('./headers');
const Response = require('./response');
const PassThrough = stream.PassThrough;

function parseHeaders(rawHeaders) {
  let headers = new Header();
  for (const name of Object.keys(rawHeaders)) {
    headers.set(name, rawHeaders[name]);
  }
  return headers;
}
function fetch(input, options) {
  return new Promise((resolve, reject) => {
    let request = new Request(input, options);
    const send = request.url.protocol === 'https:' ? https : http;
    // 发送请求
    let req = send.request(request.url, {
      method: request.method,
      headers: request.headers.valueOf(),
      auth: request.auth,
      agent: request.agent,
      createConnection: request.createConnection
    });
    if (request.timeout > 0) { // 设置请求超时
      req.setTimeout(request.timeout, () => {
        reject(new Error(`request to ${request.url} timeout`));
      });
    }
    req.on('error', (err) => {
      reject(new Error(`request to ${request.url} failed, reason: ${err.message}`));
    });
    req.on('response', (res) => {
      const headers = parseHeaders(res.headers);
      let body = res.pipe(new PassThrough());
      const responseOptions = {
        url: request.url,
        status: res.statusCode,
        statusText: res.statusMessage,
        headers: headers
      };
      const codings = headers.get('Content-Encoding');
      const zlibOptions = {
        flush: zlib.Z_SYNC_FLUSH,
        finishFlush: zlib.Z_SYNC_FLUSH
      };
      if (codings === 'gzip') { // gzip
        body = body.pipe(zlib.createGunzip(zlibOptions));
      }
      else if (codings === 'deflate') { // deflate
        body = body.pipe(zlib.createInflate(zlibOptions));
      }
      else if (codings === 'br') { // br
        body = body.pipe(zlib.createBrotliDecompress());
      }
      resolve(new Response(body, responseOptions));
    });
    // 写入 body
    if (request.body == null) {
      req.end();
    }
    else if (Buffer.isBuffer(request.body)) {
      req.write(request.body);
      req.end();
    }
    else {
      request.body.pipe(req);
    }
  });
}

module.exports = fetch;
